#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdbool.h>
#include "queue.h"

#define DEBUG		0		// 1:开启测试 | 0: 关闭



// 初始化循环双端链表
struct queue* queue_create(int _node_sz){
	struct _Node *head = (struct _Node*) calloc(1,sizeof(struct _Node));
	struct queue* queue = (struct queue*) calloc(1,sizeof(struct queue));
	if(head==NULL | queue==NULL){
		perror("init_queue:");
		return NULL;
	}
	queue->head = head;
	queue->_node_data_size = _node_sz;
	head->prev = head;
	head->next = head;

	return queue;
}

int queue_is_empty(struct queue *queue){
	struct _Node *head = queue->head;
	if(head->prev == head->next && head->next == head){
		return true;
	}
	return false;
}

// 入队操作
int queue_push(struct queue *queue, void *data, int sz) {
	struct _Node *_node = (struct _Node*)calloc(1, sizeof(struct _Node) + queue->_node_data_size);
	if(_node == NULL){
		printf("enqueue malloc failed in %s\n", __FUNCTION__);
		return -1;
	}

	if (sz < queue->_node_data_size) {
		printf("sz is too small \n");
		return -1;
	}
	memcpy(_node->data, data, queue->_node_data_size);

	// 尾插法
	struct _Node *head = queue->head;
	struct _Node* old_tail = head->prev;
	if(queue_is_empty(queue)){
		head->prev = _node;
		head->next = _node;
		_node->prev = head;
		_node->next = head;
	}

	_node->prev = old_tail;
	_node->next = head;
	old_tail->next = _node;
	head->prev = _node;

	return 0;
}

// 出队操作
void queue_pop(struct queue *queue) {
	if(queue_is_empty(queue)){
		return;
	}
	struct _Node *head = queue->head;
	struct _Node *old_next = head->next;
	struct _Node *new_next = old_next->next;
	head->next = new_next;
	new_next->prev = head;

	free(old_next);
}

// 查询队列头部元素
int queue_first(struct queue *queue, void* data, int sz) {
	if(queue_is_empty(queue)){return 0;}
	if (sz < queue->_node_data_size) {
		printf("sz is too small\n");
		return -1;
	}

	memcpy(data, &(queue->head->next->data[0]), queue->_node_data_size);
	return 0;
}


void queue_destroy(struct queue *queue) {
	if (queue == NULL) return;

	while (!queue_is_empty(queue)){
		queue_pop(queue);
	}
	free((queue)->head);
	free(queue);
}



#if DEBUG

int main(int argc, char** argv){
	int i;

	struct queue *queue;
	char str1[] = "hello world";
	char str2[] = "Linux";
	char data;
	queue = queue_create(1);
	for (i=0; i< strlen(str1); i++) {
		queue_push(queue,&str1[i], 1);
	}

	for (i=0; i< strlen(str1); i++) {
		queue_push(queue,&str2[i], 1);
	}

	for(i=0;i<strlen(str1) + strlen(str2);i++){
		queue_first(queue, &data, 1);
		queue_pop(queue);
		printf("out: %c\n",data);
	}
	queue_pop(queue);
	queue_destroy(&queue);
	return 0;
}

#endif